#include "TcpUnix.hpp"

int		TcpUnix::OpenSocket(int	&fdSocket)
{
  ProtoType	*proto;
  
  if ((proto = GetProtoByName()) == NULL)
    {
      puts("Protocol name is not available in this server.");
      return (-1);
    }
  if ((fdSocket = Socket(proto)) == -1)
    {
      puts("Can't open local socket.");
      return (-1);
    }
  return (0);
}

template<typename A, typename B>
A Convert(B t)
{
  return ((A)t);
}

int TcpUnix::Connect(int fd,
		     SockInfo &si)
{
  int len;
  SocketInfo sin;

  sin = si.GetSin();
  len = sizeof(sin);
  return connect(fd, Convert<const struct sockaddr *, SocketInfo *>(&sin), len);
}

TcpUnix::TcpUnix()
{  
}

TcpUnix::~TcpUnix()
{
  
}

int TcpUnix::Write(int	fd,
	       char	*buf,
	       int	size)
{
  return write(fd, static_cast<void *>(buf), size);  
}

int TcpUnix::Read(int	fd,
	      char	*buf,
	      int	size)
{
  return read(fd, static_cast<void *>(buf), size);
}

int TcpUnix::NetRead(int	fd,
		     Buffer	&buf)
{
  int		size;
  int		cnt;
  int		total;

  if (buf.GetAlreadyRead() == -1)
    {
      size = buf.GetBufferSize();
      total = Read(fd, Convert<char*, int*>(&size), sizeof(buf.GetBufferSize()));
      if (total < 0)
	return (-1);
      else if (total == 0)
	return (0);
      buf.SetBufferSize(size);
      buf.SetBuffer(new char[buf.GetBufferSize()]);
      buf.SetAlreadyRead(0);
      return (1);
    }
  total = buf.GetAlreadyRead();
  size = buf.GetBufferSize();
  if  ((cnt = Read(fd, &((buf.GetBuffer())[total]), size - total)) < 0)
    return (-1);
  else if (cnt == 0)
    return (0);
  else
    buf.SetAlreadyRead(buf.GetAlreadyRead() + cnt);
  return (1);  
}

int TcpUnix::NetWrite(int	fd,
		      Buffer	&buf)
{
  int		total;
  int		size;
  int		cnt;

  size = buf.GetBufferSize();
  if (buf.GetAlreadyRead() == -1)
    {
      if ((total = Write(fd, Convert<char *, int *>(&size), sizeof(buf.GetBufferSize()))) < 0)
	return (-1);
      else if (total == 0)
	return (0);
      buf.SetAlreadyRead(0);
      return (1);
    }
  total = buf.GetAlreadyRead();
  if ((cnt = Write(fd, &((buf.GetBuffer())[total]), size - total)) < 0)
    return (-1);
  else if (cnt == 0)
    return (0);
  else
    buf.SetAlreadyRead(buf.GetAlreadyRead() + cnt);
  return (1);
}

ProtoType     *TcpUnix::GetProtoByName()
{
  return getprotobyname("TCP");
}

int           TcpUnix::Socket(ProtoType                         *proto)
{
  return socket(AF_INET, SOCK_STREAM, proto->p_proto);
}

int TcpUnix::Select(int fd,
		    FdInfos &fdInfos,
		    TimeVal &tim)
{
  return select(fd + 1, &(fdInfos.GetReadf()), &(fdInfos.GetWritef()), NULL, &(tim.GetTim()));
}

int TcpUnix::Accept(int fd,
		    SockInfo &si)
{
  int		len;
  SocketInfo	sin;
  
  sin = si.GetSin();
  len = sizeof(sin);
  return accept(fd, Convert<struct sockaddr *, SocketInfo *>(&sin), Convert<socklen_t *, int *>(&len));
}

int TcpUnix::Bind(int fd,
		  SockInfo &si)
{
  int		len;
  SocketInfo	sin;
  
  sin = si.GetSin();
  len = sizeof(sin);
  return bind(fd, Convert<struct sockaddr *, SocketInfo *>(&sin), len);
}

int TcpUnix::Listen(int fd)
{
  return listen(fd, BACKLOG);
}
